//
//  CalendarView.swift
//  DaGlass
//
//  Created by 李然 on 2023/4/6.
//

import UIKit
import MoyoungLib
import SnapKit

class CalendarView: View {
    
    var selectDate: ((Date) -> Void)?
    
    private let viewModel: CalendarViewModel
    
    init(calendarType: CalendarType, defaultDate: Date = Date()) {
        self.viewModel = CalendarViewModel(calendarType: calendarType,
                                           defaultDate: defaultDate)
        super.init(frame: .zero)
    }
    
    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        log.debug(#function)
    }
    
    func addTo(_ view: UIView?) {
        
        initUI()
        
        if let view = view {
            view.addSubview(self)
            self.showView()
        } else {
            keyWindow.addSubview(self)
            self.showView()
        }
    }
    
    private func initUI() {
        
        self.frame = self.keyWindow.bounds
        
        addSubview(blackView)
        
        addSubview(contentView)
        contentView.snp.makeConstraints { make in
            make.bottom.equalTo(-self.keyWindow.bounds.height)
            make.width.equalToSuperview()
        }
        contentView.setNeedsLayout()
        contentView.layoutIfNeeded()
        
        self.todayButton.rx.tap.subscribe(onNext: { [weak self] _ in
            guard let `self` = self else { return }
            self.selectDate?(Date())
            self.dismissView()
        }).disposed(by: rx.disposeBag)
        
        self.leftButton.rx.tap.subscribe(onNext: { [weak self] _ in
            guard let `self` = self else { return }
            self.collectionView.setContentOffset(CGPoint(x: CGFloat(self._page - 1) * self.collectionView.width, y: 0), animated: true)
        }).disposed(by: rx.disposeBag)
        
        self.rightButton.rx.tap.subscribe(onNext: { [weak self] _ in
            guard let `self` = self else { return }
            self.collectionView.setContentOffset(CGPoint(x: CGFloat(self._page + 1) * self.collectionView.width, y: 0), animated: true)
        }).disposed(by: rx.disposeBag)

        collectionView.reloadData()
        collectionView.scrollToItem(at: viewModel.getDetaultCellIndexPath(), at: .right, animated: false)
        updateAndNotifyScrolling()
    }
    
    private func showView() {
        
        self.layoutIfNeeded()
        UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 1.3, options: []) {
            self.blackView.alpha = 1
            let ssss = self.contentView.height - self.keyWindow.bounds.height
            self.contentView.snp.updateConstraints { make in
                make.bottom.equalTo(ssss)
            }
            self.layoutIfNeeded()
        } completion: { _ in
            
        }
    }
    
    @objc private func dismissView() {
        
        self.layoutIfNeeded()
        UIView.animate(withDuration: 0.3) {
            self.blackView.alpha = 0
            self.contentView.snp.updateConstraints { make in
                make.bottom.equalTo(-self.keyWindow.bounds.height)
            }
            self.layoutIfNeeded()
        } completion: { _ in
            self.removeFromSuperview()
        }
    }
    
    private lazy var contentView: View = {
        let view = View()
        view.layer.cornerRadius = 13
        view.layer.masksToBounds = true
        view.backgroundColor = R.color.common_2_bg_page()
        view.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.top.equalTo(kStatusBarHeight + 12)
        }
        view.addSubview(leftButton)
        leftButton.snp.makeConstraints { make in
            make.centerY.equalTo(titleLabel)
            make.leading.equalTo(20)
        }
        view.addSubview(rightButton)
        rightButton.snp.makeConstraints { make in
            make.centerY.equalTo(titleLabel)
            make.trailing.equalTo(-20)
        }
        view.addSubview(weekCalendarView)
        weekCalendarView.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(15)
            make.leading.equalTo(8)
            make.trailing.equalTo(-8)
        }
        view.addSubview(collectionView)
        collectionView.snp.makeConstraints { make in
            make.top.equalTo(weekCalendarView.snp.bottom).offset(15)
            make.leading.equalTo(8)
            make.trailing.equalTo(-8)
            let width = (kScreenWidth - 2 * 8)/7*6
            make.height.equalTo(width)
        }
        view.addSubview(todayButton)
        todayButton.snp.makeConstraints { make in
            make.top.equalTo(collectionView.snp.bottom).offset(22)
            make.size.equalTo(CGSize(width: kScreenWidth - 40, height: 56))
            make.centerX.equalToSuperview()
            make.bottom.equalTo(-20)
        }
        return view
    }()
    
    private lazy var titleLabel: Label = {
        let label = Label()
        label.textColor = R.color.common_3_text()
        label.font = Fonts.systemFont(ofSize: 18)
        label.numberOfLines = 0
        label.text = "2022年九月"
        return label
    }()
    
    private lazy var leftButton: Button = {
        let btn = Button(type: .custom)
        btn.setTitleColor(R.color.common_23_text_second(), for: .normal)
        btn.titleLabel?.font = Fonts.systemFont(ofSize: 13)
        btn.setTitle("八月", for: .normal)
        return btn
    }()
    
    private lazy var rightButton: Button = {
        let btn = Button(type: .custom)
        btn.setTitleColor(R.color.common_23_text_second(), for: .normal)
        btn.titleLabel?.font = Fonts.systemFont(ofSize: 13)
        btn.setTitle("十月", for: .normal)
        return btn
    }()
    
    private lazy var weekCalendarView: CalendarWeekView = {
        let weekCalendarView = CalendarWeekView()
        weekCalendarView.backgroundColor = R.color.common_2_bg_page()
        weekCalendarView.updateDatas(datas: [R.string.localizable.common_sunday(),
                                             R.string.localizable.common_monday(),
                                             R.string.localizable.common_tuesday(),
                                             R.string.localizable.common_wednesday(),
                                             R.string.localizable.common_thursday(),
                                             R.string.localizable.common_friday(),
                                             R.string.localizable.common_saturday()])
        return weekCalendarView
    }()
    
    private lazy var collectionView: UICollectionView = {
        let layout = CalendarCollectionViewFlowLayout()
        layout.viewModel = self.viewModel
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.backgroundColor = R.color.common_2_bg_page()
        collectionView.isPagingEnabled = true
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.register(CalendarViewCell.self, forCellWithReuseIdentifier: CalendarViewCell.reuseIdentifier)
        return collectionView
    }()
    
    private lazy var todayButton: ScaleButton = {
        let btn = ScaleButton(type: .custom)
        btn.setTitle(R.string.localizable.common_calendar_today(), for: .normal)
        return btn
    }()
    
    private lazy var blackView: UIView = {
        let view = UIView(frame: self.keyWindow.bounds)
        view.backgroundColor = UIColor.black.withAlphaComponent(0.25)
        view.alpha = 0
        view.isUserInteractionEnabled = true
        view.addOnClickListener(target: self, action: #selector(dismissView))
        return view
    }()

    private lazy var keyWindow: UIView = {
        return UIApplication.getKeyWindow() ?? UIView()
    }()
    
    private var _page: Int = 0

}

extension CalendarView: UICollectionViewDataSource {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return viewModel.numberOfSections()
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 42
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CalendarViewCell.reuseIdentifier, for: indexPath) as! CalendarViewCell
        let model = viewModel.cellForItemAtCellModel(indexPath: indexPath)
        cell.set(calendarType: viewModel.calendarType, model: model)
        return cell
    }
}

extension CalendarView: UICollectionViewDelegate {
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cellModel = viewModel.cellForItemAtCellModel(indexPath: indexPath)
        guard cellModel.type == .normal else {
            return
        }
        viewModel.selectedItem?.isSelected = false
        cellModel.isSelected = true
        viewModel.selectedItem = cellModel
        collectionView.reloadData()
        
        let date = Date.init(year: cellModel.year,
            month: cellModel.month,
            day: cellModel.day,
            hour: 0,
            minute: 0)
        self.selectDate?(date)
        self.dismissView()
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        self.updateAndNotifyScrolling()
    }
    
    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        self.updateAndNotifyScrolling()
    }
    
    func updateAndNotifyScrolling() {
        var page: Int = 0
        
        let offsetX = ceilf(Float(self.collectionView.contentOffset.x))
        let width = self.collectionView.bounds.size.width
        guard width > 0 else {
            return
        }
        page = Int(floor(offsetX / Float(width)))
        
        page = page > 0 ? page : 0
        _page = page
        guard viewModel.calendarSections.count > page else {
            return
        }
        let curSection = viewModel.calendarSections[page]
        self.titleLabel.text = "\(curSection.year)\(R.string.localizable.common_unit_year())\(curSection.monthFirstDay.toString(.custom("MMMM")))"
        if page > 0 {
            let preSection = viewModel.calendarSections[page - 1]
            self.leftButton.setTitle(preSection.monthFirstDay.toString(.custom("MMMM")), for: .normal)
            self.leftButton.isHidden = false
        } else {
            self.leftButton.setTitle("", for: .normal)
            self.leftButton.isHidden = true
        }
        if page < viewModel.calendarSections.count - 1 {
            let nextSection = viewModel.calendarSections[page + 1]
            self.rightButton.setTitle(nextSection.monthFirstDay.toString(.custom("MMMM")), for: .normal)
            self.rightButton.isHidden = false
        } else {
            self.rightButton.setTitle("", for: .normal)
            self.rightButton.isHidden = true
        }
    }
}

open class CalendarCollectionViewFlowLayout: UICollectionViewFlowLayout {
    
    weak var viewModel: CalendarViewModel?
    
    public override init() {
        super.init()
        
        self.scrollDirection = .horizontal
        let width = (kScreenWidth - 2 * 8)/7
        self.itemSize = CGSize(width: width, height: width)
        self.minimumLineSpacing = 0
        self.minimumInteritemSpacing = 0
        self.sectionInset = UIEdgeInsets.zero
    }
    
    public required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        
        return super.layoutAttributesForElements(in: rect)?.map { attrs in
            let attrscp = attrs.copy() as! UICollectionViewLayoutAttributes
            self.applyLayoutAttributes(attrscp)
            return attrscp
        }
    }
    
    override open func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        
        if let attrs = super.layoutAttributesForItem(at: indexPath) {
            let attrscp = attrs.copy() as! UICollectionViewLayoutAttributes
            self.applyLayoutAttributes(attrscp)
            return attrscp
        }
        return nil
    }
    
    func applyLayoutAttributes(_ attributes: UICollectionViewLayoutAttributes) {
        guard attributes.representedElementKind == nil else { return }
        
        guard let collectionView = self.collectionView else { return }
        
        var xCellOffset = CGFloat(attributes.indexPath.item % 7) * self.itemSize.width
        var yCellOffset = CGFloat(attributes.indexPath.item / 7) * self.itemSize.height
        
        if let lineCount = self.viewModel?.calendarSections[attributes.indexPath.section].lineCount {
            if lineCount == 4 {
                yCellOffset = (CGFloat(attributes.indexPath.item / 7) + 1 ) * self.itemSize.height
            }
            if lineCount == 5 {
                yCellOffset = (CGFloat(attributes.indexPath.item / 7) + 0.5 ) * self.itemSize.height
            }
        }
        
        let offset = CGFloat(attributes.indexPath.section)
        xCellOffset += offset * collectionView.frame.size.width
        
        attributes.frame = CGRect(
            x: xCellOffset,
            y: yCellOffset,
            width: self.itemSize.width,
            height: self.itemSize.height
        )
    }
}
